<!DOCTYPE HTML><html lang="en">
<HEAD>

<meta name="copyright" content="Copyright (c) IBM Corporation and others 2012, 2020. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." >

<meta charset="utf-8">
<LINK REL="STYLESHEET" HREF="../book.css" TYPE="text/css">
<TITLE>Console Shell</TITLE>

<link rel="stylesheet" type="text/css" HREF="../book.css">
</HEAD>
<BODY>
  <h1>Console Shell</h1>

  <h2>General Features</h2>

  <p>The Equinox OSGi console is based on Apache Felix Gogo, which provides a Unix-like shell
  for OSGi frameworks. The OSGi console is useful for runtime configuration and management of the
  framework and bundles deployed within it. It can also be useful for debugging and troubleshooting
  of OSGi-based applications.</p>

  <p>The Equinox console provides:</p>
  <ul>
      <li>support for console sessions over Telnet and SSH protocols</li>
      <li><a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASRefGuide.html">JAAS</a> based user authentication</li>
      <li>public key based authentication</li>
      <li>tab completion and command history</li>
  </ul>
  <p>This guide shows how to configure and use the console in a minimal OSGi runtime.</p>

  <h2>Starting a Command Line Session</h2>

  <p>The minimal bundle set needed to start Equinox with the console on the command line is as follows:</p>

  <ul>
    <li>org.apache.felix.gogo.command_&lt;version&gt;.jar</li>
    <li>org.apache.felix.gogo.runtime_&lt;version&gt;.jar</li>
    <li>org.apache.felix.gogo.shell_&lt;version&gt;.jar</li>
    <li>org.eclipse.equinox.console_&lt;version&gt;.jar</li>
    <li>org.eclipse.osgi_&lt;version&gt;.jar</li>
  </ul>

  <p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
  <a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>

  <p>Extract these bundles into a directory, then inside that directory create a
  <b>configuration/config.ini</b> file with the following content:</p>

  <pre>
    osgi.bundles=\
        org.apache.felix.gogo.runtime,\
        org.apache.felix.gogo.command,\
        org.apache.felix.gogo.shell,\
        org.eclipse.equinox.console</pre>

  <p>Now this minimal Equinox configuration can be started with a console available on the command
  line, by passing the <code>-console</code> option, for example:</p>

  <pre>
    $ java -jar org.eclipse.osgi_*.jar -console
    osgi> ss
    "Framework is launched."
    
    id      State       Bundle
    0       ACTIVE      org.eclipse.osgi_3.15.200.v20200214-1600
    1       ACTIVE      org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
    2       ACTIVE      org.apache.felix.gogo.command_1.0.2.v20170914-1324
    3       ACTIVE      org.apache.felix.gogo.shell_1.1.0.v20180713-1646
    4       ACTIVE      org.eclipse.equinox.console_1.4.0.v20190819-1430
    osgi> exit
    Really want to stop Equinox? (y/n; default=y)</pre>

  <h2>Starting a Telnet Session</h2>

  <p>Starting the console in a Telnet session is enabled by passing a port number with the
  <code>-console</code> option, for example:</p>

  <pre>
    $ java -jar org.eclipse.osgi_*.jar -console 1234</pre>

  <p>Once Equinox is started, connect to the Telnet session from another terminal using the
  port number that was specified above:</p>

  <pre>
    $ telnet localhost 1234
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    osgi> ss
    "Framework is launched."
    
    id      State       Bundle
    0       ACTIVE      org.eclipse.osgi_3.15.200.v20200214-1600
    1       ACTIVE      org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
    2       ACTIVE      org.apache.felix.gogo.command_1.0.2.v20170914-1324
    3       ACTIVE      org.apache.felix.gogo.shell_1.1.0.v20180713-1646
    4       ACTIVE      org.eclipse.equinox.console_1.4.0.v20190819-1430
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection closed by foreign host.</pre>

  <p>It is possible to set the port in the <b>configuration/config.ini</b> file with the
  addition of this line:</p>

  <pre>
    osgi.console=1234
    # ... or ...
    osgi.console=localhost:1234</pre>

  <p>The <code>osgi.console</code> property specifies the port (and optionally the hostname) on
  which the console should listen for Telnet connections without needing to pass the <code>-console</code>
  option at all, but if <code>-console</code> is passed it will override any setting present in the
  <b>configuration/config.ini</b> file.</p>

  <h2>Starting an SSH Session With JAAS Authentication</h2>
  
  <p>To start a console session in an SSH session, a few more bundles are needed:</p>

  <ul>
    <li>org.apache.felix.gogo.command_&lt;version&gt;.jar</li>
    <li>org.apache.felix.gogo.runtime_&lt;version&gt;.jar</li>
    <li>org.apache.felix.gogo.shell_&lt;version&gt;.jar</li>
    <li>org.apache.sshd.osgi_&lt;version&gt;.jar</li>
    <li>org.eclipse.equinox.console_&lt;version&gt;.jar</li>
    <li>org.eclipse.equinox.console.jaas.fragment_&lt;version&gt;.jar</li>
    <li>org.eclipse.equinox.console.ssh_&lt;version&gt;.jar</li>
    <li>org.eclipse.osgi_&lt;version&gt;.jar</li>
    <li>org.slf4j.api_&lt;version&gt;.jar</li>
  </ul>

  <p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
  <a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>

  <p>Extract these bundles into a directory, then inside that directory create a
  <b>configuration/config.ini</b> file with the following content:</p>

  <pre>
    osgi.bundles=\
        org.apache.felix.gogo.runtime,\
        org.apache.felix.gogo.command,\
        org.apache.felix.gogo.shell,\
        org.apache.sshd.osgi,\
        org.eclipse.equinox.console,\
        org.eclipse.equinox.console.jaas.fragment,\
        org.eclipse.equinox.console.ssh@start,\
        org.slf4j.api
    osgi.console.ssh=127.0.0.1:1234
    osgi.console.ssh.useDefaultSecureStorage=true</pre>

  <p>Equinox uses JAAS to authenticate SSH sessions, the default login provider of which must be
  configured by creating a JAAS configuration file, for example by creating a file
  <b>configuration/console.auth.config</b> with the following content:</p>

  <pre>
    equinox_console {
        org.eclipse.equinox.console.jaas.SecureStorageLoginModule REQUIRED;
    };</pre>

  <p>Then when starting Equinox, it must be told where the JAAS configuration is by setting the
  <code>java.security.auth.login.config</code> system property. The default JAAS login provider stores
  its credentials in a one-way encrypted store file that must be specified with the
  <code>org.eclipse.equinox.console.jaas.file</code> system property:</p>

  <pre>
    $ java -Dssh.server.keystore=configuration/hostkey.ser \
           -Dorg.eclipse.equinox.console.jaas.file=configuration/store \
           -Djava.security.auth.login.config=configuration/console.auth.config \
           -jar org.eclipse.osgi_*.jar</pre>

  <p>The default JAAS login provider dynamically creates one default user <b>equinox</b> with password
  <b>equinox</b>. After logging in with these credentials for the first time, the user will be prompted
  to create a new account and the default account will be removed.</p>

  <p>Once Equinox is started, connect to the SSH session from another terminal using the hostname and
  port specified in the <b>configuration/config.ini</b> file:</p>

  <pre>
    $ ssh -p 1234 equinox@127.0.0.1
    The authenticity of host '[127.0.0.1]:1234 ([127.0.0.1]:1234)' can't be established.
    RSA key fingerprint is SHA256:7x3eOsDRM5lyL5vRsVREy8hIawIfqRiZ7CBnk6GkfRA.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '[127.0.0.1]:1234' (RSA) to the list of known hosts.
    Password authentication
    Password: 
    Currently the default user is the only one; since it will be deleted after first login, create a new user:
    username: mbooth
    password: 
    Confirm password: 
    roles: admin
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to 127.0.0.1 closed.</pre>

  <p>The password must be at least 8 symbols long and the username may contain alphanumerical
  characters, underscores and dots. On subsequent connections the user will be required to supply the
  newly created credentials:</p>

  <pre>
    $ ssh -p 1234 mbooth@127.0.0.1
    Password authentication
    Password: 
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to 127.0.0.1 closed.</pre>

  <p>Once logged in there are various commands for administering users. Type <b>help</b> at the OSGi
  console prompt to explore commands to perform the following functions:</p>
  <ul>
    <li>adding, deleting, listing users</li>
    <li>reseting and changing passwords</li>
    <li>adding and removing user roles</li>
  </ul>

  <h3>Custom JAAS Authentication Login Providers</h3>

  <p>Only authentication is implemented in the default JAAS login provider so by default all
  authenticated users have similar rights. Roles exist to allow authorization to be added in
  custom JAAS login providers.</p>

  <p>A custom JAAS login provider can be used by creating a bundle fragment that extends the
  <b>org.apache.sshd.osgi</b> bundle. This fragment is used to provide or import the package
  of the custom login provider. This is necessary for the SSH system to be able to load the
  provider class.</p>

  <p>If a custom JAAS login provider is used, then the <code>osgi.console.ssh.useDefaultSecureStorage</code>
  property must not be set in the <b>configuration/config.ini</b> at all and the custom login provider
  must be specified in the <b>configuration/console.auth.config</b> file instead of the default
  entry there.</p>

  <h2>Starting an SSH Session With Public Key Authentication</h2>

  <p>It's common to want to use public key authentication with SSH and it is possible to configure
  Equinox to do that instead of using JAAS authentication. First an SSH key-pair should be created
  as normal and then a file created that contains the list of authorized keys that Equinox should
  consult when users attempt to connect:</p>

  <pre>
    $ ssh-keygen -f ~/.ssh/equinox
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/mbooth/.ssh/equinox
    Your public key has been saved in /home/mbooth/.ssh/equinox.pub
    The key fingerprint is:
    SHA256:0k7MSbLLzhhzI7Gw6oSYEx8Fv5UpNHMPTdOUDj8rplQ mbooth@thinkpad-p50
    The key's randomart image is:
    +---[RSA 3072]----+
    |  . + oooo..     |
    |   + + =o.o      |
    |    + = o+       |
    |   . + BE.+      |
    |. o o o.S  o     |
    |o+ + +.=o .      |
    |=.o =.=o..       |
    |.o   O..         |
    |o.  . o          |
    +----[SHA256]-----+
    
    $ cat ~/.ssh/equinox.pub > configuration/equinox_authorized_keys</pre>

  <p>Next the following line must be removed from the <b>configuration/config.ini</b> file:</p>

  <pre>
    # Remove this line to use public key authentication
    # Must only be present when using the default JAAS login provider
    osgi.console.ssh.useDefaultSecureStorage=true</pre>

  <p>Now when starting Equinox, instead of telling it about the JAAS configuration, it must be
  told about the authorized keys file by setting the <code>ssh.server.authorized_keys</code>
  system property:</p>

  <pre>
    $ java -Dssh.server.keystore=configuration/hostkey.ser \
           -Dssh.server.authorized_keys=configuration/equinox_authorized_keys \
           -jar org.eclipse.osgi_*.jar</pre>

  <p>And that allows users to use their SSH keys instead of a username/password pair when
  connecting to the SSH console session:</p>

  <pre>
    $ ssh -i ~/.ssh/equinox -p 1234 localhost
    The authenticity of host '[localhost]:1234 ([127.0.0.1]:1234)' can't be established.
    RSA key fingerprint is SHA256:m2JKy2fRZA1aqvxHBBe+Awsgk98ryI29fH03Rg7jeHw.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '[localhost]:1234' (RSA) to the list of known hosts.
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to localhost closed.</pre>

  <p>The authorized keys file given to Equinox will be read every time a connection is made,
  which allows adding and removing of keys dynamically at runtime.</p>

  <h3>Custom Public Key Authentication</h3>

  <p>Equinox also supports customizing the public key authentication mechanism. If no
  specific authorized keys file is configured via system property then the OSGi service
  registry will be searched for available authenticators. To enable this feature set the
  <code>ssh.custom.publickeys.auth</code> system property to <code>true</code>.</p>

  <h2>Starting Telnet and SSH Sessions Together</h2>

  <p>It is possible to start Equinox console sessions over both Telnet and SSH simultaneously.
  For this, both the <code>osgi.console</code> and <code>osgi.console.ssh</code> properties must
  be specified in the <b>configuration/config.ini</b> file:</p>

  <pre>
    # Telnet session
    osgi.console=&lt;hostname&gt;:&lt;port&gt;
    # SSH session
    osgi.console.ssh=&lt;hostname&gt;:&lt;port&gt;</pre>

  <p>These properties specify the port on which to listen and the hostname (or IP address) to
  which it binds for incoming connections.</p>

  <p>For both properties, the hostname (or IP address) is optional and may be omitted. If the
  hostname is omitted, then localhost is assumed. If the hostname is the same for both properties,
  or both hostnames are omitted then the SSH session must have a different port number to the
  Telnet session.</p>

  <h2>Using the Configuration Admin Service</h2>

  <p>It is possible to configure Telnet and SSH console sessions through the Configuration Admin
  Service instead of using the <code>osgi.console</code> and <code>osgi.console.ssh</code>
  properties. This is helpful in more complex scenarios, for example when you want to run different
  instances of the console in different subsystems of the framework. In this case if the port is
  configured through a system property, the same value is used for all console instances and only one 
  will be able to bind to the socket.</p>

  <p>To enable this feature, the Configuration Admin bundle and it's dependencies must be added
  to the Equinox instance:</p>

  <ul>
    <li>org.eclipse.equinox.cm_&lt;version&gt;.jar</li>
    <li>org.eclipse.osgi.services_&lt;version&gt;.jar</li>
    <li>org.eclipse.osgi.util_&lt;version&gt;.jar</li>
  </ul>

  <p>All of these bundles are available in the <b>Equinox SDK</b> zip file available from the
  <a href="https://download.eclipse.org/equinox/">Equinox Downloads</a> site.</p>

  <p>And then in the <b>configuration/config.ini</b> file, the <code>osgi.console.useConfigAdmin</code>
  property must be used in place of the usual configuration properties:</p>

  <pre>
    # Remove these properties:
    #osgi.console=&lt;hostname&gt;:&lt;port&gt;
    #osgi.console.ssh=&lt;hostname&gt;:&lt;port&gt;

    # Use the Config Admin Service instead:
    osgi.console.useConfigAdmin=true</pre>

  <p>Now a custom bundle must be written that uses the Configuration Admin Service to configure
  Telnet and SSH console sessions. The Persistent Identity (PID) for the Telnet configuration is
  <code>osgi.console.telnet</code> and for the SSH configuration is <code>osgi.console.ssh</code>.
  Both configurations have the following properties, all expecting values of type String:</p>

  <ul>
    <li><code>host</code></li>
    <li><code>port</code></li>
    <li><code>enabled</code></li>
  </ul>

  <p>The <code>enabled</code> property determines if the Telnet or SSH session is to be started
  at all. If the value is <code>true</code>, it is started. If the value is <code>false</code>,
  or the property <code>enabled</code> is absent, the Telnet or SSH session is not started.</p>

  <h2>Console Command Usage</h2>

  <p>The Equinox console works similarly to Unix-style shells. Multiple commands can be sent when
  separated by a semi-colon and the output of commands may be piped to the input of other commands.
  For example:</p>

  <pre>
    osgi> ss | grep slf4j
    8       ACTIVE      org.slf4j.api_1.7.2.v20121108-1250
    true
    osgi> stop 8 ; start 8</pre>

  <p>IO redirection can be simulated with the <b>cat</b> and <b>tac</b> commands. For example:</p>

  <pre>
    osgi> ss | tac out.txt
    osgi> cat out.txt | grep slf4j
    8       ACTIVE      org.slf4j.api_1.7.2.v20121108-1250
    true</pre>

  <p>The console also has standard command line editing features such as:</p>

  <ul>
    <li>backspace - deletes the character to the left of the cursor</li>
    <li>delete - deletes the character on the cursor position</li>
    <li>home/end - moves the cursor to the beginning/end of the command line</li>
    <li>left/right arrow - moves the cursor one character left/right</li>
    <li>up/down arrow - moves backward/forward one entry in the command history</li>
    <li>pageup/pagedown - moves to the first/last entry of the command history</li>
    <li>tab - command completion (described in more detail below)</li>
  </ul>

  <p>However some of these editing features are only supported when using the console via a
  Telnet or SSH session.</p>

  <h3>Command Scopes</h3>

  <p>Equinox console commands have the notion of command scope. The scope is a kind of namespace
  that can be used, for example, to differentiate between commands with the same name, but provided
  by different providers.</p>

  <p>The scope is a prefix of the command name, separated from it by a colon. When writing the
  command in the console, specifying the scope is optional: A command may be written as
  <code>command_name</code> or <code>scope:command_name</code>. If the scope is not specified,
  then the command with this name from the default scope is used. If there is no such command in
  the default scope, all scopes are searched.</p>

  <p>If there is more than one command with the specified name in different, non-default scopes,
  it is not guaranteed which one will be actually executed. Therefore, if there are commands
  with the same name but in different scopes, the scope prefix must be specified explicitly
  with the command name to ensure that exactly the desired command is executed.</p>

  <p>The Equinox console is now based on Apache Felix Gogo, which has a different way of
  implementing console commands than the traditional Equinox way. Equinox adapts these legacy
  commands for the Gogo-based shell and makes them available in the <b>equinox</b> scope.
  For compatibility, the default scope is the <b>equinox</b> scope.</p>

  <h3>Getting Help for Commands</h3>

  <p>Typing <b>help</b> (or <b>man</b>) at the OSGi console prompt with no arguments, the help for
  all available commands is displayed. To limit the output to commands from a specific scope, the
  <code>-scope &lt;scope_name&gt;</code> parameter can be passed to the <b>help</b> command:</p>
  
  <pre>
    osgi> help -scope equinox

    close - shutdown and exit
       scope: equinox

    diag - Displays unsatisfied constraints for the specified bundle(s)
       scope: equinox
       parameters:
          Bundle[]   IDs of bundle(s), for which to display unsatisfied constraints

    ...etc...</pre>
  
  <p>The help text for a specific command can be shown by passing a
  <code>command_name</code> or <code>scope:command_name</code> to the <b>help</b> command. If
  the scope is not specified, then the help text is shown for the command from the default scope
  if it exists:</p>

  <pre>
    osgi> help headers

    headers - print bundle headers
       scope: equinox
       parameters:
          Bundle[]   bundles to print headers for

    osgi> help felix:headers

    headers - display bundle headers
       scope: felix
       parameters:
          Bundle[]   target bundles</pre>

  <p>The default help command provided by the Apache Felix Gogo shell does not provide help
  for the legacy Equinox commands, which are adapted by the Equinox console for the Gogo shell.
  For this reason the Equinox console provides its own <b>help</b> command in the <b>equinox</b> scope
  that delegates to the default help command whilst also providing help for legacy commands.</p>

  <h3>Closing Console Sessions</h3>

  <p>When using the Equinox console standalone on the command line, the <b>exit</b> command can be
  used to terminate Equinox and return to the system command prompt.</p>

  <p>For both Telnet and SSH sessions, the session can be closed without terminating Equinox with
  the <b>disconnect</b> command.</p>

  <h2>Implementing Custom Console Commands</h2>

  <p>Traditionally in Equinox commands are provided by a class implementing the
  <code>org.eclipse.osgi.framework.console.CommandProvider</code> interface. The Equinox console
  provides an adapter from this legacy type of command to the new type of command used in Gogo but it is
  preferred that new commands are implemented as Gogo commands directly.</p>

  <p>Commands for Apache Felix Gogo are plain old Java object (POJO) classes with all the commands
  implemented as public methods. The methods may have arbitrary arguments. These classes are
  registered as services, with two special properties:</p>

  <ul>
    <li><code>osgi.command.scope</code> - specifies the scope of the command</li>
    <li><code>osgi.command.function</code> - specifies the commands provided by this service;
    this is a string array containing the names of public methods in the implementing class
    that can be executed as commands</li>
  </ul>

  <p>Gogo commands also have the notion of converters and formatters.</p>

  <p>A converter is a class which converts the arguments passed at the OSGi console prompt,
  to the actual arguments that the command accepts. For example, the command may have one
  argument of type <code>Bundle</code>. A converter might accept a long integer and finds the
  bundle with this ID. Then the command may be called with the ID of the bundle as an argument,
  the converter will convert it to the corresponding <code>Bundle</code> object and the command
  method will be called with this object as an argument.</p>

  <p>A formatter is a class which displays a result returned by a command method.</p>

  <p>For more information on Gogo commands, see the <a href="http://felix.apache.org/documentation/subprojects/apache-felix-gogo.html">Gogo documentation</a>.</p>

  <h2>Implementing Custom Tab Completion</h2>

  <p>The Equinox console provides tab completion and allows implementors to provide their own
  custom completion providers. This feature is available only when connecting through a Telnet
  or SSH session. Completion is available for:</p>

  <ul>
    <li>command names</li>
    <li>variable names passed as command arguments - these must be previously defined in the session</li>
    <li>file names passed as command arguments</li>
  </ul>

  <p>When the <code>tab</code> key is typed, all possible candidates for completion for the current
  word are searched. If there is only one possible completion, the current word is automatically
  completed. If there is more than one option, all are displayed. The user can then cycle through the
  possible completions by hitting <code>tab</code> multiple times, until the desired completion
  candidate is selected.</p>

  <p>If longest common prefix of all available completion candidates is longer than the current word,
  then the current word is completed automatically to this prefix before choosing the final completion.
  For example, if the following completions are available for the word <b>bun</b>:</p>

  <ul>
    <li>bundles</li>
    <li>bundle</li>
    <li>bundlelevel</li>
  </ul>

  <p>Then the current word is completed automatically to <b>bundle</b> and the user can continue
  typing normally or, by hitting <code>tab</code> again, they can cycle through the possible
  completions.</p>

  <p>A custom completer should implement the <code>org.eclipse.equinox.console.common.Completer</code>
  interface provided by the Equinox console bundle. It has the single method <code>getCandidates</code>,
  which take as parameters the whole command line and the current cursor position within it, and returns
  a map of completion candidates to positions in the command line at which the completion begins.</p>

</BODY>
</HTML>